package com.lry.jvm.rtda.heap;

import com.lry.jvm.util.Util;

//根据方法的描述符解析 ()V
public class MethodDescriptorParser {

    private String row;
    private int offset;
    private MethodDescriptor methodDescriptor;

    public MethodDescriptor parseMethodDescriptor(String descriptor) {
        this.row = descriptor;
        this.methodDescriptor = new MethodDescriptor();
        startParams();
        parseParamTypes();
        endParams();
        parseReturnTypes();
        finish();
        return methodDescriptor;
    }

    private void finish() {
        if(offset!=row.length()){
            causePanic();
        }
    }

    private void parseReturnTypes() {
        if(readChar()=='V'){
            methodDescriptor.setReturnType("V");
            return;
        }

        unreadChar();
        String type = parseFieldType();
        if("".equals(type)){
            causePanic();
        }
        methodDescriptor.setReturnType(type);
    }

    private void endParams() {
        if(readChar()!=')'){
            causePanic();
        }
    }
    //  public main([Ljava/lang/String;Lcom/lry/jvm/example/exp1/Exp1;Ljava/lang/Integer;)V
    private void parseParamTypes() {
        while(true){
            String type = parseFieldType();
            if("".equals(type)){
                break;
            }
            try {
                methodDescriptor.addParameterType(type);
            }catch (Exception e){
                System.err.println(row);
            }

        }
    }

    private String parseFieldType() {
        char c = readChar();
        switch (c){
            case 'B':
                return "B";
            case 'C':
                return "C";
            case 'D':
                return "D";
            case 'F':
                return "F";
            case 'I':
                return "I";
            case 'J':
                return "J";
            case 'S':
                return "S";
            case 'Z':
                return "Z";
            case 'L':
                return parseObjectType();
            case '[':
                return parseArrayType();
            default:
                unreadChar();
                return "";
        }
    }
    //[Ljava/lang/String;
    private String parseArrayType() {
        int start = offset-1;
        parseFieldType();
        int end = offset;
        return row.substring(start,end);
    }
    //Lcom/lry/jvm/example/exp1/Exp1;
    private String parseObjectType() {
        String unread = row.substring(offset);
        int index = unread.indexOf(";");
        if(index==-1){
            causePanic();
            return "";
        }

        int start = offset-1;
        int end = offset + index + 1;
        offset = end;
        return row.substring(start,end);
    }

    private void startParams() {
        if(readChar()!='('){
            causePanic();
        }
    }

    public void causePanic(){
        Util.panic("Bad descriptor:" + row);
    }

    public char readChar(){
        return row.charAt(offset++);
    }
    public void unreadChar(){
        offset--;
    }

}
